// https://www.shadertoy.com/view/XsXSWS

precision lowp float;
varying vec2 vTextureCoord;
uniform float iTime;
uniform vec2 iResolution;


mat2 rotz(float angle)
{
    mat2 m;
    m[0][0] = cos(angle); m[0][1] = -sin(angle);
    m[1][0] = sin(angle); m[1][1] = cos(angle);
    return m;
}

float rand(vec2 co){
    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}


// float fbm(vec2 uv)
// {
//     float n = (texture(iChannel1, uv).r - 0.5) * 0.5;
//     n += (texture(iChannel1, uv * 2.0).r - 0.5) * 0.5 * 0.5;
//     n += (texture(iChannel1, uv * 3.0).r - 0.5) * 0.5 * 0.5 * 0.5;
    
// 	return n + 0.5;
// }

// procedural noise from IQ
vec2 hash( vec2 p )
{
	p = vec2( dot(p,vec2(127.1,311.7)),
			 dot(p,vec2(269.5,183.3)) );
	return -1.0 + 2.0*fract(sin(p)*43758.5453123);
}

float noise( in vec2 p )
{
	const float K1 = 0.366025404; // (sqrt(3)-1)/2;
	const float K2 = 0.211324865; // (3-sqrt(3))/6;
	
	vec2 i = floor( p + (p.x+p.y)*K1 );
	
	vec2 a = p - i + (i.x+i.y)*K2;
	vec2 o = (a.x>a.y) ? vec2(1.0,0.0) : vec2(0.0,1.0);
	vec2 b = a - o + K2;
	vec2 c = a - 1.0 + 2.0*K2;
	
	vec3 h = max( 0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 );
	
	vec3 n = h*h*h*h*vec3( dot(a,hash(i+0.0)), dot(b,hash(i+o)), dot(c,hash(i+1.0)));
	
	return dot( n, vec3(70.0) );
}

float fbm(vec2 uv)
{
	float f;
	mat2 m = mat2( 1.6,  1.2, -1.2,  1.6 );
	f  = 0.5000*noise( uv ); uv = m*uv;
	f += 0.2500*noise( uv ); uv = m*uv;
	f += 0.1250*noise( uv ); uv = m*uv;
	f += 0.0625*noise( uv ); uv = m*uv;
	f = 0.5 + 0.5*f;
	return f;
}

// -----------------------------------------------
vec4 mainImage( in vec2 uvIn ) {
	uvIn.y = 1.0 - uvIn.y;
    vec2 fragCoord = uvIn * iResolution;
    
    vec2 uv = fragCoord.xy / iResolution.xy;
    vec2 _uv = uv;
    uv -= vec2(0.5);
    uv.y /= iResolution.x / iResolution.y;
    vec2 centerUV = uv;
    
    // height variation from fbm
    float variationH = fbm(vec2(iTime * .3)) * 1.1;
    
    // flame "speed"
    vec2 offset = vec2(0.0, -iTime * 0.15);
    
    // flame turbulence
    float f = fbm(uv * 0.1 + offset); // rotation from fbm
    float l = max(0.1, length(uv)); // rotation amount normalized over distance
	uv += rotz( ((f - 0.5) / l) * smoothstep(-0.2, .4, _uv.y) * 0.45) * uv;    
    
    // flame thickness
    float flame = 1.3 - length(uv.x) * 5.0;
    
    // bottom of flame 
    float blueflame = pow(flame * .9, 15.0);
    blueflame *= smoothstep(.2, -1.0, _uv.y);
    blueflame /= abs(uv.x * 2.0);
    blueflame = clamp(blueflame, 0.0, 1.0);
    
    // flame
    flame *= smoothstep(1., variationH * 0.5, _uv.y);
	flame = clamp(flame, 0.0, 1.0);
    flame = pow(flame, 3.);
    flame /= smoothstep(1.1, -0.1, _uv.y);    
	
    // colors
    vec4 col = mix(vec4(1.0, 1., 0.0, 0.0), vec4(1.0, 1.0, .6, 0.0), flame);
    col = mix(vec4(1.0, .0, 0.0, 0.0), col, smoothstep(0.0, 1.6, flame));
    vec4 fragColor = col;
    
	// a bit blueness on the bottom
    vec4 bluecolor = mix(vec4(0.0, 0.0, 1.0, 0.0), fragColor, 0.95);
    fragColor = mix(fragColor, bluecolor, blueflame);
    
    // clear bg outside of the flame
    fragColor *= flame;
    fragColor.a = flame;
    
    // bg halo
    float haloSize = 0.5;
    float centerL = 1.0 - (length(centerUV + vec2(0.0, 0.1)) / haloSize);
    vec4 halo = vec4(.8, .3, .3, 0.0) * 1.0 * fbm(vec2(iTime * 0.035)) * centerL + 0.02;
    vec4 finalCol = mix(halo, fragColor, fragColor.a);
    fragColor = finalCol;

    // just a hint of noise
    fragColor *= mix(rand(uv) + rand(uv * .45), 1.0, 0.9);
    fragColor = clamp(fragColor, 0.0, 1.0);
	fragColor.z = fragColor.x;
 	fragColor.y /= 2.0;
    
	return fragColor;
}

void main(void) {
	gl_FragColor = mainImage(vTextureCoord.xy);
}
